﻿using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Linq;
using System.Threading;

namespace Gtk.Relay
{
    public class RelayHelper
    {
        private readonly ConcurrentQueue<byte> _queue = new ConcurrentQueue<byte>();
        private readonly AutoResetEvent _resetEvent = new AutoResetEvent(false);

        public RelayHelper(SerialPort serialPort)
        {
            SerialPort = serialPort;
            SerialPort.DataReceived += SerialPort_DataReceived;
            SerialPort.Disposed += SerialPort_Disposed;
        }

        public SerialPort SerialPort { get; }

        /// <summary>字节超时。数据包间隔，默认20ms</summary>
        public int ByteTimeout { get; set; } = 20;


        private void SerialPort_Disposed(object sender, EventArgs e)
        {
            SerialPort.Disposed -= SerialPort_Disposed;
            SerialPort.DataReceived -= SerialPort_DataReceived;
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            this.WaiteMore();
            if (this.SerialPort.BytesToRead <= 0)
            {
                return;
            }

            var buf = new byte[this.SerialPort.BytesToRead];
            var read = this.SerialPort.Read(buf, 0, buf.Length);
            Console.WriteLine("----------------");
            Console.WriteLine(string.Join(",", buf.Take(read).Select(i => i.ToString("X2"))));
        }
        /// <summary>
        /// 
        /// </summary>
        ///<remarks>https://github.com/NewLifeX/X/blob/187ce26005df7e8190b892a2df1555c4c702e9b4/NewLife.Core/Net/SerialTransport.cs</remarks>
        private void WaiteMore()
        {
            var sp = SerialPort;

            var ms = ByteTimeout;
            var end = DateTime.Now.AddMilliseconds(ms);
            var count = sp.BytesToRead;
            while (sp.IsOpen && end > DateTime.Now)
            {
                Thread.Sleep(ms);
                if (count != sp.BytesToRead)
                {
                    end = DateTime.Now.AddMilliseconds(ms);
                    count = sp.BytesToRead;
                }
            }
        }

        private void SendCommand(byte[] bytes)
        {
            if (SerialPort == null || !SerialPort.IsOpen)
            {
                return;
            }

            var crc16 = Crc16.ComputeChecksum(bytes);
            var crcBytes = new byte[2];
            crcBytes[0] = Convert.ToByte(crc16 & 0xff);
            crcBytes[1] = Convert.ToByte((crc16 >> 8) & 0xff);
            var newData = new byte[bytes.Length + 2];
            Buffer.BlockCopy(bytes, 0, newData, 0, bytes.Length);
            Buffer.BlockCopy(crcBytes, 0, newData, bytes.Length, 2);
            SerialPort.Write(newData, 0, newData.Length);
            Thread.Sleep(100);
        }

        /// <summary>
        ///     开启
        /// </summary>
        /// <param name="board"></param>
        /// <param name="number"></param>
        public void Open(byte board, byte number)
        {
            SendCommand(new byte[] { board, 0x05, 0x00, number, 0xFF, 0x00 });
        }

        /// <summary>
        ///     关闭
        /// </summary>
        /// <param name="board"></param>
        /// <param name="number"></param>
        public void Close(byte board, byte number)
        {
            SendCommand(new byte[] { board, 0x05, 0x00, number, 0x00, 0x00 });
        }

        /// <summary>
        ///     翻转
        /// </summary>
        /// <param name="board"></param>
        /// <param name="number"></param>
        public void Toggle(byte board, byte number)
        {
            SendCommand(new byte[] { board, 0x05, 0x00, number, 0x55, 0x00 });
        }
    }
}